package com.xwj.ioc;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

/**
 * ioc简单实现
 * @author xwj
 * @date 2020/4/10
 */
public class SimpleIOC {
    private Map<String, Object> beanMap = new HashMap<String, Object>(64);

    public SimpleIOC(String configLocation) throws Exception {
        initBeanMap(configLocation);
    }

    private void initBeanMap(String configLocation) throws Exception {
        // 加载配置文件
        // 初始化bean容器
        InputStream inputStream = new FileInputStream(configLocation);
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = factory.newDocumentBuilder();
        Document doc = docBuilder.parse(inputStream);
        Element root = doc.getDocumentElement();
        NodeList nodes = root.getChildNodes();
        // 遍历标签
        for (int i = 0, len = nodes.getLength(); i < len; i++) {
            Node node = nodes.item(i);
            if (node instanceof Element) {
                Element ele = (Element) node;
                String id = ele.getAttribute("id");
                String className = ele.getAttribute("class");
                // 反射创建bean
                Class beanClass = null;
                try {
                    beanClass = Class.forName(className);
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                    return;
                }
                Object bean = beanClass.newInstance();
                // bean属性注入
                // 遍历 <property> 标签
                NodeList propertyNodes = ele.getElementsByTagName("property");
                for (int j = 0, pLen = propertyNodes.getLength(); j < pLen; j++) {
                    Node propertyNode = propertyNodes.item(j);
                    if (propertyNode instanceof Element) {
                        Element propertyElement = (Element) propertyNode;
                        String name = propertyElement.getAttribute("name");
                        String value = propertyElement.getAttribute("value");
                        // 设置字段属性权限可访问
                        Field declaredField = bean.getClass().getDeclaredField(name);
                        declaredField.setAccessible(true);
                        if(value != null && !value.equals("")) {
                            declaredField.set(bean, value);
                        } else {
                            String ref = propertyElement.getAttribute("ref");
                            if(ref == null || ref.equals("")) {
                                throw new IllegalArgumentException("ref config error");
                            }
                            // 将引用填充到字段中
                            declaredField.set(bean, getBean(ref));
                        }
                        // 将bean注册到容器中
                        registerBean(id, bean);
                    }
                }

            }
        }
    }

    private void registerBean(String id, Object bean) {
        beanMap.put(id, bean);
    }

    public Object getBean(String beanName) {
        Object bean = beanMap.get(beanName);
        if (bean == null) {
            throw new RuntimeException("there is no bean with name " + beanName);
        }
        return bean;
    }
}
